//
//  SBPlayer.swift
//  sh
//
//  Created by xgp on 2017/5/8.
//  Copyright © 2017年 xyz. All rights reserved.
//

import Foundation
import UIKit
import AVFoundation
//填充模式枚举值
enum SBLayerVideoGravity {
    case ResizeAspect,ResizeAspectFill,Resize
}
//播放状态枚举值
enum SBPlayerStatus {
    case  Failed,
    ReadyToPlay,
    Unknown,
    Buffering,
    Playing,
    Stopped
}


class SBPlayer:UIView,SBControlViewDelegate,SBPauseOrPlayViewDelegate,UIGestureRecognizerDelegate {
    
    
    var player:AVPlayer?{
        get{return self.playerLayer?.player}
        set{self.playerLayer?.player = newValue}
    }
    
    var item:AVPlayerItem?
    //总时长
    var totalTime:CMTime?
    //当前时间
    var currentTime:CMTime?
    //资产AVURLAsset
    var anAsset:AVURLAsset?
    //播放器Playback Rate
    var rate:Float?{
        get{return self.player?.rate}
    }
    //播放状态
    var status:SBPlayerStatus?
    //videoGravity设置屏幕填充模式，（只写）
    var mode: SBLayerVideoGravity?
    //是否正在播放
    var isPlaying:Bool = false
    //是否全屏
    var isFullScreen = false
    //设置标题
    var title:String?{
        get{return self.titleLabel?.text}
        set{ self.titleLabel?.text = newValue }
    }
    
    
    var playerLayer:AVPlayerLayer?
           //当前播放url
    var url:URL?
    //底部控制视图
    var controlView:SBControlView?
    //暂停和播放视图
    var pauseOrPlayView:SBPauseOrPlayView?
    //原始约束
    var oldConstriants:[NSLayoutConstraint]?
    //添加标题
    var titleLabel:UILabel?
    //加载动画
    var activityIndeView:UIActivityIndicatorView?
    
    static var count = 0
    //与url初始化
    init(withurl url:URL) {
        super.init(frame: CGRect(x: 0, y: 0, width: 0, height: 0))
        self.url = url
        self.setupPlayerUI()
        print("sbplayer 初始化")
        self.assetWithURL(url: url)
    }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }
    //公用同一个资产请使用此方法初始化
    init(withAsset asset:AVURLAsset){
        super.init(frame: CGRect(x: 0, y: 0, width: 0, height: 0))
        self.setupPlayerUI()
        self.setupPlayerWithAsset(asset: asset)
    }
    
    //将播放url放入资产中初始化播放器
    func assetWithURL(url:URL){
        let options:Dictionary  = [AVURLAssetPreferPreciseDurationAndTimingKey:true]
        self.anAsset  = AVURLAsset(url: url,options:options)
        let keys = ["duration"]
        self.controlView?.currentTime = "00:00"
        self.controlView?.totalTime = "00:00"
        
        
        self.anAsset?.loadValuesAsynchronously(forKeys: keys, completionHandler: {
            var error:NSError? = nil
            let tracksStatus:AVKeyValueStatus = (self.anAsset?.statusOfValue(forKey: "duration", error: &error))!
            switch(tracksStatus){
            case .loaded:
                DispatchQueue.global(qos: .default).async {
                    if CMTIME_IS_INDEFINITE((self.anAsset?.duration)!) {
                        let second:Float   = Float(self.anAsset!.duration.value) / Float(self.anAsset!.duration.timescale)
                        self.controlView?.totalTime = self.convertTime(second: second)
                        self.controlView?.minValue = 0
                        self.controlView?.maxValue = second
                    }
                }
            case .failed:
                print("AVKeyValueStatusFailed失败,请检查网络,plist中是否添加App Transport Security Settings")
            case .cancelled:
                print("AVKeyValueStatusCancelled取消")
            case .unknown:
                print("AVKeyValueStatusUnknownw未知")
            case .loading:
                print("AVKeyValueStatusLoading正在加载")
                
            }
        })
        self.setupPlayerWithAsset(asset: self.anAsset!)
    }
    
    func setMode(mode:SBLayerVideoGravity) -> Void {
        switch (mode) {
        case .ResizeAspect:
            self.playerLayer?.videoGravity = AVLayerVideoGravityResizeAspect;
            break;
        case .ResizeAspectFill:
            self.playerLayer?.videoGravity = AVLayerVideoGravityResizeAspectFill;
            break;
        case .Resize:
            self.playerLayer?.videoGravity = AVLayerVideoGravityResize;
            break;
        }
    }
    
    
    //将数值转换成时间
    func convertTime(second:Float)->String{
        let d =  Date(timeIntervalSince1970:TimeInterval(second))
        let formatter:DateFormatter = DateFormatter()
        if second/3600 >= 1 {
            formatter.dateFormat = "HH:mm:ss"
        } else {
            formatter.dateFormat = "mm:ss"
        }
        let showtimeNew:String = formatter.string(from: d)
        return showtimeNew;
    }
    
    override func draw(_ rect: CGRect) {
        self.setupPlayerUI()
    }
    
    //MARK: 设置界面 在此方法下面可以添加自定义视图，和删除视图
    func setupPlayerUI(){
       
        self.activityIndeView?.startAnimating()
        //添加标题
        self.addTitle()
        //添加点击事件
        self.addGestureEvent()
        //添加播放和暂停按钮
        self.addPauseAndPlayBtn()
        //添加控制视图
        self.addControlView()
        //添加加载视图
        self.addLoadingView()
    }
    
    func setupPlayerWithAsset(asset:AVURLAsset){
        self.item = AVPlayerItem(asset: asset)
//        self.player = AVPlayer(playerItem: self.item)
        self.playerLayer = AVPlayerLayer(player: AVPlayer(playerItem: self.item))
        self.playerLayer?.displayIfNeeded()
        self.playerLayer?.videoGravity = AVLayerVideoGravityResizeAspectFill
        self.playerLayer?.frame = self.bounds
        self.layer.addSublayer(playerLayer!)
        
        self.addPeriodicTimeObserver()
        //添加KVO
        self.addKVO()
        //添加消息中心
        self.addNotificationCenter()
    }
    func addKVO(){
        //监听状态属性
        self.item?.addObserver(self, forKeyPath: "status", options: .new, context: nil)
        //监听网络加载情况属性
        self.item?.addObserver(self, forKeyPath: "loadedTimeRanges", options: .new, context: nil)
        
        //监听播放的区域缓存是否为空
        self.item?.addObserver(self, forKeyPath: "playbackBufferEmpty", options: .new, context: nil)
        
        //缓存可以播放的时候调用
        self.item?.addObserver(self, forKeyPath: "playbackLikelyToKeepUp", options: .new, context: nil)
        
        //监听暂停或者播放中
        self.player?.addObserver(self, forKeyPath: "rate", options: .new, context: nil)
    }
    //添加消息中心
    func addNotificationCenter() -> Void {
        NotificationCenter.default.addObserver(self, selector: #selector(SBPlayerItemDidPlayToEndTimeNotification(notification:)), name: Notification.Name.AVPlayerItemDidPlayToEndTime, object: self.player?.currentItem)
        
        NotificationCenter.default.addObserver(self, selector: #selector(deviceOrientationDidChange(notification:)), name: Notification.Name.UIDeviceOrientationDidChange, object: nil)
        
        NotificationCenter.default.addObserver(self, selector: #selector(willResignActive(notification:)), name: Notification.Name.UIApplicationWillResignActive, object: nil)
        
    }
    
    func willResignActive(notification:Notification) -> Void {
        if isPlaying{
            self.setSubViewsIsHide(isHide: false)
            self.pause()
            self.pauseOrPlayView?.imageBtn?.isSelected = false
        }
        
    }
    
    func deviceOrientationDidChange(notification:Notification) -> Void {
        let interfaceOrientation=UIApplication.shared.statusBarOrientation
        switch interfaceOrientation {
        case .landscapeLeft,.landscapeRight:
            isFullScreen = true
            if let _=self.oldConstriants{
                self.oldConstriants = self.getCurrentVC().view.constraints
            }
            self.controlView?.updateConstraints()
            //删除UIView animate可以去除横竖屏切换过渡动画
            UIView.animate(withDuration: 0.3, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0, options: .transitionCurlUp, animations: {
                UIApplication.shared.keyWindow?.addSubview(self)
                self.snp.makeConstraints({ (make) in
                    make.edges.equalTo(UIApplication.shared.keyWindow!)
                })
                
            }, completion: nil)
            
        case .portraitUpsideDown,.portrait:
            isFullScreen = false
            self.removeFromSuperview()
            self.getCurrentVC().view.addSubview(self)
            UIView.animate(withDuration: 0.5, delay: 0, options: .curveLinear, animations: {
                if let _ = self.oldConstriants {
                    self.getCurrentVC().view.addConstraints(self.oldConstriants!)}
            }, completion: nil)
        case .unknown:
            print("UIInterfaceOrientationUnknown")
        }
        self.getCurrentVC().view.layoutIfNeeded()
    }
    
    func SBPlayerItemDidPlayToEndTimeNotification(notification:Notification) -> Void {
        self.item?.seek(to: kCMTimeZero)
        self.setSubViewsIsHide(isHide: false)
        SBPlayer.count = 0
        self.pause()
        self.pauseOrPlayView?.imageBtn?.isSelected = false
    }
    var playbackTimerObserver:Any?
    //FIXME: Tracking time,跟踪时间的改变
    func addPeriodicTimeObserver(){
        weak var weakSelf = self
        playbackTimerObserver = self.player!.addPeriodicTimeObserver(forInterval: CMTimeMake(Int64(1.0), Int32(1.0)), queue: nil, using: { (time) in
            let timeValue = Double((weakSelf?.item?.currentTime().value)!)
            let timeScale = Double((weakSelf?.item?.currentTime().timescale)!)
            weakSelf?.controlView?.value = Float(timeValue/timeScale)
            if CMTIME_IS_INDEFINITE((self.anAsset?.duration)!){
                weakSelf?.controlView?.currentTime = "\(timeValue/timeScale)"
            }
            
            weakSelf?.setSubViewsIsHide(isHide: SBPlayer.count >= 5)
            SBPlayer.count+=1
        })
    }
    //TODO: KVO
    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
        if keyPath == "status" {
//            let itemStatus:AVPlayerStatus = change?[NSKeyValueChangeKey.newKey] as! AVPlayerStatus
            let itemStatus:AVPlayerStatus = AVPlayerStatus(rawValue: change?[NSKeyValueChangeKey.newKey] as! Int)!
            
            switch itemStatus {
            case AVPlayerStatus.unknown:
                self.status = SBPlayerStatus.Unknown
                print("AVplayer status unknown")
            case .readyToPlay:
                status = SBPlayerStatus.ReadyToPlay;
                print("AVPlayerItemStatusReadyToPlay");
            case .failed:
                status = SBPlayerStatus.Failed;
                print("AVPlayerItemStatusFailed");
            default:
                break
            }
        }else if keyPath == "loadedTimeRanges" {//监听播放器的下载进度
            let loadedTimeRanges = self.item?.loadedTimeRanges
            let timeRange = loadedTimeRanges?.first?.timeRangeValue// 获取缓冲区域
            let startSeconds = CMTimeGetSeconds((timeRange?.start)!)
            let durationSeconds = CMTimeGetSeconds((timeRange?.duration)!);
            let timeInterval = startSeconds + durationSeconds;// 计算缓冲总进度
            let duration = self.item!.duration
            let totalDuration = CMTimeGetSeconds(duration);
            //缓存值
            self.controlView?.bufferValue=Float(timeInterval / totalDuration);
            
        } else if keyPath == "playbackLikelyToKeepUp" {
            print("缓冲达到可播放")
            self.activityIndeView?.stopAnimating()
        } else if keyPath == "rate" {//当rate==0时为暂停,rate==1时为播放,当rate等于负数时为回放
            if let v = change?[NSKeyValueChangeKey.newKey] as? Int {
                if v == 0{
                    isPlaying = true
                    status = SBPlayerStatus.Playing
                }else{
                    isPlaying = false
                    status = SBPlayerStatus.Stopped
                }
            }else{
                print("observe error")
            }
        }
    }
    
    
    func addLoadingView(){
        if nil == self.activityIndeView {
            activityIndeView = UIActivityIndicatorView(activityIndicatorStyle: .whiteLarge)
            activityIndeView?.hidesWhenStopped = true
        }
        self.addSubview(self.activityIndeView!)
        self.activityIndeView?.snp.makeConstraints({ (make) in
            make.width.height.equalTo(80);
            make.center.equalTo(self);
        })
    }
    func addTitle(){
        if nil == titleLabel {
            titleLabel = UILabel()
            titleLabel?.backgroundColor = UIColor.clear
            titleLabel?.font = UIFont.systemFont(ofSize: 15)
            titleLabel?.numberOfLines = 3
            titleLabel?.textColor = UIColor.white
            titleLabel?.textAlignment = .center
        }
        self.addSubview(self.titleLabel!)
        self.titleLabel?.snp.makeConstraints({ (make) in
            make.left.right.equalTo(self);
            make.top.equalTo(self).offset(12);
            make.width.equalTo(self.snp.width);
        })
    }
    func addGestureEvent(){
        let tap:UITapGestureRecognizer = UITapGestureRecognizer(target:self, action:#selector(handleTapAction))
        tap.delegate = self
        self.addGestureRecognizer(tap);
    }
    func handleTapAction(gesture:UITapGestureRecognizer){
        self.setSubViewsIsHide(isHide: false);
        SBPlayer.count = 0;
    }
    
    func addPauseAndPlayBtn(){
        if nil == pauseOrPlayView {
            pauseOrPlayView = SBPauseOrPlayView()
            pauseOrPlayView?.delegate = self
            pauseOrPlayView?.backgroundColor = UIColor.clear
        }
        
        self.addSubview(self.pauseOrPlayView!)
        self.pauseOrPlayView?.snp.makeConstraints({ (make) in
            make.edges.equalTo(self)
        })
    }
    
    func addControlView(){
        if nil == self.controlView {
            controlView = SBControlView()
            controlView?.delegate = self
            controlView?.backgroundColor = UIColor.red
            //            这里报错，先注释掉
            if let other = self.pauseOrPlayView?.imageBtn?.gestureRecognizers {
                controlView?.tapGesture?.require(toFail: other.first!)
            }
        }
        
        self.addSubview(self.controlView!)
        
        self.controlView?.snp.makeConstraints({ (make) in
            make.left.right.bottom.equalTo(self)
            make.height.equalTo(44)
        })
        self.layoutIfNeeded()
    }
    
    //设置子视图是否隐藏
    func setSubViewsIsHide(isHide:Bool){
        self.controlView?.isHidden = isHide;
        self.pauseOrPlayView?.isHidden = isHide;
        self.titleLabel?.isHidden = isHide;
    }
    //播放
    func play(){
        if let _ = self.player{
            print("开始播放")
            self.player?.play()
        }else {
          print("播放失败！\(self.playerLayer) \(self.playerLayer?.player)")
        }
    }
    //暂停
    func pause(){
        if let _ = self.player {
            self.player?.pause()
        }
    }
    
    func setRate(rate:Float) -> Void {
        self.player?.rate = Float(rate)
    }
    //停止 //移除当前视频播放下一个，调用Stop方法
    func stop(){
        self.item?.removeObserver(self, forKeyPath: "status")
        self.player?.removeTimeObserver(playbackTimerObserver as Any)
        self.item?.removeObserver(self, forKeyPath: "loadedTimeRanges")
        self.item?.removeObserver(self, forKeyPath: "playbackBufferEmpty")
        self.item?.removeObserver(self, forKeyPath: "playbackLikelyToKeepUp")
        self.player?.removeObserver(self, forKeyPath: "rate")
        
        NotificationCenter.default.removeObserver(self, name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: self.player?.currentItem)
        
        NotificationCenter.default.removeObserver(self, name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)
    }
    
    func controlView(controlView: SBControlView, withLargeButton: UIButton) {
        SBPlayer.count = 0
        if kScreenWidth < kScreenHeight {
            self.interfaceOrientation(orientation: .landscapeRight)
        }else {
            self.interfaceOrientation(orientation: .portrait)
        }
        
    }
    
    func controlView(controlView: SBControlView, draggedPositionWithSlider slider: UISlider) {
        SBPlayer.count = 0
        let pointTime = CMTimeMake(Int64(self.controlView!.value) * Int64( (self.item?.currentTime().timescale)!), (self.item?.currentTime().timescale)!)
        print("视频跳转（）")
        self.item?.seek(to: pointTime, toleranceBefore: kCMTimeZero, toleranceAfter: kCMTimeZero)
    }
    
    func controlView(controlView: SBControlView, pointSliderLocationWithCurrentValue point: CGFloat) {
        SBPlayer.count = 0
        let pointTime = CMTimeMake(Int64(self.controlView!.value) * Int64( (self.item?.currentTime().timescale)!), (self.item?.currentTime().timescale)!)
        self.item?.seek(to: pointTime, toleranceBefore: kCMTimeZero, toleranceAfter: kCMTimeZero)
        
    }
    
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
        if touch.view is SBControlView{
            return false
        }
        return true
    }
    func pauseOrPlayView(pauseOrPlayView: SBPauseOrPlayView, withState state: Bool) {
        SBPlayer.count = 0
        if state {
            self.play()
        }else{
            self.pause()
        }
    }
    //旋转方向
    func interfaceOrientation(orientation:UIInterfaceOrientation){
        if orientation == .landscapeRight || orientation == .landscapeLeft{
            //设置横屏
        }else if orientation == .portrait {
            //设置竖屏
        } else if orientation == .portraitUpsideDown {
            
        }
    }
    
    //获取当前屏幕显示的viewcontroller
    func  getCurrentVC() -> UIViewController{
        var result:UIViewController?
        var window = UIApplication.shared.keyWindow
        if window?.windowLevel != UIWindowLevelNormal {
            let windows = UIApplication.shared.windows
            for tmpWin in windows {
                if tmpWin.windowLevel == UIWindowLevelNormal {
                    window = tmpWin
                }
            }
        }
        let frontView = window?.subviews[0]
        let nextResponder =  frontView?.next
        if (nextResponder?.isKind(of: UIViewController.self))! {
            result = nextResponder as! UIViewController
        }else {
            result = window?.rootViewController
        }
        return result!
    }
    
}
